// 必要的头文件包含
#include <iostream>     // C++输入输出
#include <cstdio>      // C标准输入输出
#include <string>      // C++字符串
#include <cstring>     // C字符串操作
#include <cstdlib>     // C标准库函数
#include <unistd.h>    // Unix标准函数定义
#include <sys/types.h> // 基本系统数据类型
#include <sys/wait.h>  // wait()函数

#define N 2            // 管道的两端：读端和写端
#define NUM 1024       // 缓冲区大小

using namespace std;

// 子进程写数据的函数
void Writer(int wfd)   // wfd是管道的写端文件描述符
{
    string s = "hello, I am child";  // 待发送的消息
    pid_t self = getpid();           // 获取进程ID
    int number = 0;                  // 计数器

    char buffer[NUM];                // 数据缓冲区
    while (true)
    {
        sleep(1);    // 每次写入间隔1秒

        // 以下是发送/写入字符串的方式（被注释）
        // buffer[0] = 0;    // 清空缓冲区 
        // snprintf(buffer, sizeof(buffer), "%s-%d-%d", s.c_str(), self, number++);
        // write(wfd, buffer, strlen(buffer));

        // 当前使用的是发送单个字符的方式
        char c = 'c';
        write(wfd, &c, 1);  // 向管道写入一个字符
        number++;
        cout << number << endl;  // 显示写入次数

        if(number >= 5) break;   // 写入5次后退出
    }
}

// 父进程读数据的函数
void Reader(int rfd)   // rfd是管道的读端文件描述符
{
    char buffer[NUM];  // 数据缓冲区

    while(true)
    {
        buffer[0] = 0;  // 清空缓冲区
        // 从管道读取数据
        ssize_t n = read(rfd, buffer, sizeof(buffer));
        if(n > 0)  // 读取成功
        {
            buffer[n] = 0;  // 添加字符串结束符
            cout << "father get a message[" << getpid() << "]# " << buffer << endl;
        }
        else if(n == 0)  // 读到EOF（管道写端关闭）
        {
            printf("father read file done!\n");
            break;
        }
        else break;      // 读取出错
    }
}

int main()
{
    // 创建管道
    int pipefd[N] = {0};  // pipefd[0]读端，pipefd[1]写端
    int n = pipe(pipefd); // 调用了 pipe() 函数，用于创建一个管道，并将管道的文件描述符存储在 pipefd 数组中
    if (n < 0)           // 管道创建失败
        return 1;

    // 创建子进程
    pid_t id = fork();
    if (id < 0)          // 进程创建失败
        return 2;
        
    if (id == 0)         // 子进程
    {
        close(pipefd[0]); // 关闭读端
        Writer(pipefd[1]); // 写数据
        close(pipefd[1]); // 关闭写端
        exit(0);         // 子进程退出
    }
    
    // 父进程
    close(pipefd[1]);    // 关闭写端
    Reader(pipefd[0]);   // 读数据

    // 等待子进程结束
    pid_t rid = waitpid(id, nullptr, 0);
    if(rid < 0) return 3;

    close(pipefd[0]);    // 关闭读端

    sleep(5);            // 暂停5秒
    return 0;
}
